/*
 * Copyright (C) 2003-2009 eXo Platform SAS.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.reflext.test;

import org.reflext.api.TypeResolver;
import org.reflext.apt.*;
import org.reflext.core.TypeResolverImpl;

import javax.annotation.processing.SupportedSourceVersion;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.Map;
import java.util.HashMap;

/**
 * @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a>
 * @version $Revision$
 */
@SupportedSourceVersion(SourceVersion.RELEASE_5)
@SupportedAnnotationTypes("org.reflext.test.Type")
public class AnnotationProcessorTestRunner extends AbstractProcessor {

  /** . */
  private final ReflextUnitTest unitTest;

  /** . */
  private List<Throwable> failures = new ArrayList<Throwable>();

  /** . */
  private boolean executed;

  public AnnotationProcessorTestRunner(ReflextUnitTest unitTest) {
    this.unitTest = unitTest;
  }

  public List<Throwable> getFailures() {
    return failures;
  }


  public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {

    // Only one pass is enough
    if (executed) {
      return false;
    } else {
      executed = true;
    }

    // Get the related types
    Set<? extends Element> elts = roundEnv.getElementsAnnotatedWith(Type.class);
    Map<String, Object> types = new HashMap<String, Object>();
    for (Element elt : elts) {
      Type typeAnn = elt.getAnnotation(Type.class);
      String id = typeAnn.value();
      if (elt instanceof ExecutableElement) {
        types.put(id, ((ExecutableElement)elt).getReturnType());
      } else if (elt instanceof TypeElement) {
        types.put(id, elt);
      } else {
        throw new AssertionError();
      }
    }

    //
    TypeResolver<Object> resolver = TypeResolverImpl.create(new JavaxLangReflectionModel(), false);

    //
    try {
      TypeDomain<Object> domain = new TypeDomain<Object>(resolver, types);
      unitTest.run("org.reflext.apt", domain);
    }
    catch (Throwable e) {
      failures.add(e);
    }

    //
    return false;
  }
}